﻿using System;
using System.Collections.Generic;
using System.Text;

namespace VarintZigzigDemo
{
    /// <summary>
    /// https://blog.csdn.net/honey199396/article/details/106909428
    /// </summary>
    public class VarintUtils
    {

        public static byte[] VarintEncode(uint value, int length)
        {
            var buffer = new byte[length];
            int index = 0;
            while (true)
            {
                //0x7F 即　0111 1111
                //~ 表示取反  
                if ((value & ~0x7F) == 0)
                {
                    buffer[index] = (byte) (value & 0x7F);
                    break;
                }
                else
                {
                    //取出7位并在第8位加上标记1
                    buffer[index] = (byte)((value & 0x7F) | 0x80);
                    index++;
                    //已经处理的舍去
                    value = value >> 7;
                }
            }

            return buffer;
        }

        public static uint VarintDecode(byte[] buffer)
        {
            int value = 0;

            var len = buffer.Length;
            for (int i = 0; i < len; i++)
            {
                byte b = buffer[i];
                //0x7F 即　0111 1111
                //取出7位然后右移，因为是小端存储
                value |= (b & 0x7F) << (i * 7);
                // 0x80 即 1000 0000
                //第8位是0 说明后面没有字节了
                if ((byte) (b & 0x80) == 0)
                {
                    break;
                }
            }
            return (uint)value;
        }

        public static int VarintSize(uint value)
        {
            //位置7位，如果前面都为0，说明只有一个有效字节
            if ((value & (0xFFFFFFFF << 7)) == 0)
            {
                return 1;
            }

            if ((value & (0xFFFFFFFF << 14)) == 0)
            {
                return 2;
            }

            if ((value & (0xFFFFFFFF << 21)) == 0)
            {
                return 3;
            }

            if ((value & (0xFFFFFFFF << 28)) == 0)
            {
                return 4;
            }
            return 5;
        }


        public static uint ZigZagEncode(int n)
        {
            return (uint)((n >> 31) ^ (n << 1));
        }

        public static int ZigZagDecode(uint n)
        {
            return (int)((n >> 1) ^ -(n & 1));
        }
    }
}
